/**
 * read src letter by letter,and re-compose letters.
 */

import fs from "node:fs";
import path from "node:path";
import { createLocator } from "../utils/locate.js";
import { SourceMap } from "../sourcemap/sourcemap.js";
import { SourceMapDebug } from "../sourcemap/sourcemap-debug.js";

letterCompile({
  input: "src.txt",
  output: "tar.txt",
  sourcemap: "file", // | "file"
});

async function letterCompile(options) {
  const src = await fs.promises.readFile(
    path.resolve(import.meta.dirname, options.input),
    "utf-8"
  );
  const elements = src.split("");

  // make a pool for elements
  const pool = new Map();
  for (let i = 0; i < elements.length; i++) {
    pool.set(i, elements[i]);
  }

  // pick a random element from pool
  const pick = () => {
    if (pool.size === 0) {
      throw new Error("no more elements");
    }
    const index = Math.floor(Math.random() * pool.size);
    const available = [...pool.keys()];
    const item = pool.get(available[index]);
    pool.delete(available[index]);
    return [item, available[index]];
  };

  // compile process: sort raw elements
  let tar = "";
  const changes = []; // [tarIndex, srcIndex, item]
  for (let i = 0; i < elements.length; i++) {
    const [item, srcIndex] = pick();
    tar += item;
    changes.push([i, srcIndex, item]);
  }

  // generate sourcemap
  const sourcemap = new SourceMap({
    file: options.output,
    sources: [options.input],
    sourcesContent: [src],
  });

  const srcLocate = createLocator(src);
  const tarLocate = createLocator(tar);

  // generate sourcemap
  for (let i = 0; i < changes.length; i++) {
    const [tarIndex, srcIndex, item] = changes[i];
    const srcLoc = srcLocate(srcIndex);
    const tarLoc = tarLocate(tarIndex);

    // console.log(item, tarIndex, srcIndex);
    // console.log(item, tarLoc.line, tarLoc.column, srcLoc.line, srcLoc.column);

    // prettier-ignore
    sourcemap.addSegment(tarLoc.line, tarLoc.column, 0, srcLoc.line, srcLoc.column);
  }

  if (options.sourcemap === "inline") {
    tar += "\n// #sourceMappingURL=" + sourcemap.toURL();
  } else if (options.sourcemap === "file") {
    // write sourcemap
    await fs.promises.writeFile(
      path.resolve(import.meta.dirname, options.output + ".map"),
      sourcemap.toString(4)
    );
    tar += "\n// #sourceMappingURL=" + options.output + ".map";
  }

  // write to output
  await fs.promises.writeFile(
    path.resolve(import.meta.dirname, options.output),
    tar
  );
}
